{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-04T16:49:27.722598Z",
     "start_time": "2020-04-04T16:49:27.718011Z"
    }
   },
   "outputs": [],
   "source": [
    "def warn(*args, **kwargs):\n",
    "    pass\n",
    "import warnings\n",
    "warnings.warn = warn"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-04T16:49:28.151285Z",
     "start_time": "2020-04-04T16:49:28.117240Z"
    },
    "colab": {},
    "colab_type": "code",
    "id": "4c7Knmsem0yC"
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import os\n",
    "from time import time\n",
    "import cv2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "dXaDqQ6Nm0yH"
   },
   "source": [
    "### Build Data Loader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-04T16:51:50.962244Z",
     "start_time": "2020-04-04T16:51:50.915491Z"
    },
    "colab": {},
    "colab_type": "code",
    "id": "qPLzEcGtm0yI"
   },
   "outputs": [],
   "source": [
    "from keras.utils import Sequence\n",
    "from keras.utils import np_utils\n",
    "\n",
    "class DataGenerator(Sequence):\n",
    "    \"\"\"Data Generator inherited from keras.utils.Sequence\n",
    "    Args: \n",
    "        directory: the path of data set, and each sub-folder will be assigned to one class\n",
    "        batch_size: the number of data points in each batch\n",
    "        shuffle: whether to shuffle the data per epoch\n",
    "    Note:\n",
    "        If you want to load file with other data format, please fix the method of \"load_data\" as you want\n",
    "    \"\"\"\n",
    "    def __init__(self, directory, batch_size=1, shuffle=True, data_augmentation=True):\n",
    "        # Initialize the params\n",
    "        self.batch_size = batch_size\n",
    "        self.directory = directory\n",
    "        self.shuffle = shuffle\n",
    "        self.data_aug = data_augmentation\n",
    "        # Load all the save_path of files, and create a dictionary that save the pair of \"data:label\"\n",
    "        self.X_path, self.Y_dict = self.search_data() \n",
    "        # Print basic statistics information\n",
    "        self.print_stats()\n",
    "        return None\n",
    "        \n",
    "    def search_data(self):\n",
    "        X_path = []\n",
    "        Y_dict = {}\n",
    "        # list all kinds of sub-folders\n",
    "        self.dirs = sorted(os.listdir(self.directory))\n",
    "        one_hots = np_utils.to_categorical(range(len(self.dirs)))\n",
    "        for i,folder in enumerate(self.dirs):\n",
    "            folder_path = os.path.join(self.directory,folder)\n",
    "            for file in os.listdir(folder_path):\n",
    "                file_path = os.path.join(folder_path,file)\n",
    "                # append the each file path, and keep its label  \n",
    "                X_path.append(file_path)\n",
    "                Y_dict[file_path] = one_hots[i]\n",
    "        return X_path, Y_dict\n",
    "    \n",
    "    def print_stats(self):\n",
    "        # calculate basic information\n",
    "        self.n_files = len(self.X_path)\n",
    "        self.n_classes = len(self.dirs)\n",
    "        self.indexes = np.arange(len(self.X_path))\n",
    "        np.random.shuffle(self.indexes)\n",
    "        # Output states\n",
    "        print(\"Found {} files belonging to {} classes.\".format(self.n_files,self.n_classes))\n",
    "        for i,label in enumerate(self.dirs):\n",
    "            print('%10s : '%(label),i)\n",
    "        return None\n",
    "    \n",
    "    def __len__(self):\n",
    "        # calculate the iterations of each epoch\n",
    "        steps_per_epoch = np.ceil(len(self.X_path) / float(self.batch_size))\n",
    "        return int(steps_per_epoch)\n",
    "\n",
    "    def __getitem__(self, index):\n",
    "        \"\"\"Get the data of each batch\n",
    "        \"\"\"\n",
    "        # get the indexs of each batch\n",
    "        batch_indexs = self.indexes[index*self.batch_size:(index+1)*self.batch_size]\n",
    "        # using batch_indexs to get path of current batch\n",
    "        batch_path = [self.X_path[k] for k in batch_indexs]\n",
    "        # get batch data\n",
    "        batch_x, batch_y = self.data_generation(batch_path)\n",
    "        return batch_x, batch_y\n",
    "\n",
    "    def on_epoch_end(self):\n",
    "        # shuffle the data at each end of epoch\n",
    "        if self.shuffle == True:\n",
    "            np.random.shuffle(self.indexes)\n",
    "\n",
    "    def data_generation(self, batch_path):\n",
    "        # load data into memory, you can change the np.load to any method you want\n",
    "        batch_x = [self.load_data(x) for x in batch_path]\n",
    "        batch_y = [self.Y_dict[x] for x in batch_path]\n",
    "        # transfer the data format and take one-hot coding for labels\n",
    "        batch_x = np.array(batch_x)\n",
    "        batch_y = np.array(batch_y)\n",
    "        return batch_x, batch_y\n",
    "      \n",
    "    def normalize(self, data):\n",
    "        mean = np.mean(data)\n",
    "        std = np.std(data)\n",
    "        return (data-mean) / std\n",
    "    \n",
    "    def random_flip(self, video, prob):\n",
    "        s = np.random.rand()\n",
    "        if s < prob:\n",
    "            video = np.flip(m=video, axis=2)\n",
    "        return video    \n",
    "    \n",
    "    def uniform_sampling(self, video, target_frames=64):\n",
    "        # get total frames of input video and calculate sampling interval \n",
    "        len_frames = int(len(video))\n",
    "        interval = int(np.ceil(len_frames/target_frames))\n",
    "        # init empty list for sampled video and \n",
    "        sampled_video = []\n",
    "        for i in range(0,len_frames,interval):\n",
    "            sampled_video.append(video[i])     \n",
    "        # calculate numer of padded frames and fix it \n",
    "        num_pad = target_frames - len(sampled_video)\n",
    "        padding = []\n",
    "        if num_pad>0:\n",
    "            for i in range(-num_pad,0):\n",
    "                try: \n",
    "                    padding.append(video[i])\n",
    "                except:\n",
    "                    padding.append(video[0])\n",
    "            sampled_video += padding     \n",
    "        # get sampled video\n",
    "        return np.array(sampled_video, dtype=np.float32)\n",
    "    \n",
    "    def random_clip(self, video, target_frames=64):\n",
    "        start_point = np.random.randint(len(video)-target_frames)\n",
    "        return video[start_point:start_point+target_frames]\n",
    "    \n",
    "    def dynamic_crop(self, video):\n",
    "        # extract layer of optical flow from video\n",
    "        opt_flows = video[...,3]\n",
    "        # sum of optical flow magnitude of individual frame\n",
    "        magnitude = np.sum(opt_flows, axis=0)\n",
    "        # filter slight noise by threshold \n",
    "        thresh = np.mean(magnitude)\n",
    "        magnitude[magnitude<thresh] = 0\n",
    "        # calculate center of gravity of magnitude map and adding 0.001 to avoid empty value\n",
    "        x_pdf = np.sum(magnitude, axis=1) + 0.001\n",
    "        y_pdf = np.sum(magnitude, axis=0) + 0.001\n",
    "        # normalize PDF of x and y so that the sum of probs = 1\n",
    "        x_pdf /= np.sum(x_pdf)\n",
    "        y_pdf /= np.sum(y_pdf)\n",
    "        # randomly choose some candidates for x and y \n",
    "        x_points = np.random.choice(a=np.arange(224), size=10, replace=True, p=x_pdf)\n",
    "        y_points = np.random.choice(a=np.arange(224), size=10, replace=True, p=y_pdf)\n",
    "        # get the mean of x and y coordinates for better robustness\n",
    "        x = int(np.mean(x_points))\n",
    "        y = int(np.mean(y_points))\n",
    "        # avoid to beyond boundaries of array\n",
    "        x = max(56,min(x,167))\n",
    "        y = max(56,min(y,167))\n",
    "        # get cropped video \n",
    "        return video[:,x-56:x+56,y-56:y+56,:]  \n",
    "    \n",
    "    def color_jitter(self,video):\n",
    "        # range of s-component: 0-1\n",
    "        # range of v component: 0-255\n",
    "        s_jitter = np.random.uniform(-0.2,0.2)\n",
    "        v_jitter = np.random.uniform(-30,30)\n",
    "        for i in range(len(video)):\n",
    "            hsv = cv2.cvtColor(video[i], cv2.COLOR_RGB2HSV)\n",
    "            s = hsv[...,1] + s_jitter\n",
    "            v = hsv[...,2] + v_jitter\n",
    "            s[s<0] = 0\n",
    "            s[s>1] = 1\n",
    "            v[v<0] = 0\n",
    "            v[v>255] = 255\n",
    "            hsv[...,1] = s\n",
    "            hsv[...,2] = v\n",
    "            video[i] = cv2.cvtColor(hsv, cv2.COLOR_HSV2RGB)\n",
    "        return video\n",
    "        \n",
    "    def load_data(self, path):\n",
    "        # load the processed .npy files which have 5 channels (1-3 for RGB, 4-5 for optical flows)\n",
    "        data = np.load(path, mmap_mode='r')\n",
    "        data = np.float32(data)\n",
    "        # sampling 64 frames uniformly from the entire video\n",
    "        data = self.uniform_sampling(video=data, target_frames=64)\n",
    "        # whether to utilize the data augmentation\n",
    "        if  self.data_aug:\n",
    "            data[...,:3] = self.color_jitter(data[...,:3])\n",
    "            data = self.random_flip(data, prob=0.5)\n",
    "        # normalize rgb images and optical flows, respectively\n",
    "        data[...,:3] = self.normalize(data[...,:3])\n",
    "        data[...,3:] = self.normalize(data[...,3:])\n",
    "        return data\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "tiRBuTO8m0yY"
   },
   "source": [
    "### Build Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-04T16:51:51.550714Z",
     "start_time": "2020-04-04T16:51:51.544436Z"
    },
    "colab": {},
    "colab_type": "code",
    "id": "FfP2e_X-m0ya"
   },
   "outputs": [],
   "source": [
    "from keras.models import Sequential, Input, Model\n",
    "from keras.layers import Dense, Flatten, Conv3D, MaxPooling3D, Dropout, BatchNormalization, Activation, LeakyReLU, Add, Multiply\n",
    "from keras.regularizers import l2\n",
    "from keras.layers.core import Lambda\n",
    "from keras.layers.core import Lambda"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-04T16:51:51.698326Z",
     "start_time": "2020-04-04T16:51:51.694124Z"
    }
   },
   "outputs": [],
   "source": [
    "# extract the rgb images \n",
    "def get_rgb(input_x):\n",
    "    rgb = input_x[...,:3]\n",
    "    return rgb\n",
    "\n",
    "# extract the optical flows\n",
    "def get_opt(input_x):\n",
    "    opt= input_x[...,3:5]\n",
    "    return opt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-04T16:51:52.349970Z",
     "start_time": "2020-04-04T16:51:51.857125Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"model_3\"\n",
      "__________________________________________________________________________________________________\n",
      "Layer (type)                    Output Shape         Param #     Connected to                     \n",
      "==================================================================================================\n",
      "input_2 (InputLayer)            (None, 64, 224, 224, 0                                            \n",
      "__________________________________________________________________________________________________\n",
      "lambda_7 (Lambda)               (None, 64, 224, 224, 0           input_2[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "lambda_8 (Lambda)               (None, 64, 224, 224, 0           input_2[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_23 (Conv3D)              (None, 64, 224, 224, 448         lambda_7[0][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_31 (Conv3D)              (None, 64, 224, 224, 304         lambda_8[0][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_24 (Conv3D)              (None, 64, 224, 224, 784         conv3d_23[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_32 (Conv3D)              (None, 64, 224, 224, 784         conv3d_31[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling3d_13 (MaxPooling3D) (None, 64, 112, 112, 0           conv3d_24[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling3d_17 (MaxPooling3D) (None, 64, 112, 112, 0           conv3d_32[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_25 (Conv3D)              (None, 64, 112, 112, 2320        max_pooling3d_13[0][0]           \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_33 (Conv3D)              (None, 64, 112, 112, 2320        max_pooling3d_17[0][0]           \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_26 (Conv3D)              (None, 64, 112, 112, 784         conv3d_25[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_34 (Conv3D)              (None, 64, 112, 112, 784         conv3d_33[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling3d_14 (MaxPooling3D) (None, 64, 56, 56, 1 0           conv3d_26[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling3d_18 (MaxPooling3D) (None, 64, 56, 56, 1 0           conv3d_34[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_27 (Conv3D)              (None, 64, 56, 56, 3 4640        max_pooling3d_14[0][0]           \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_35 (Conv3D)              (None, 64, 56, 56, 3 4640        max_pooling3d_18[0][0]           \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_28 (Conv3D)              (None, 64, 56, 56, 3 3104        conv3d_27[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_36 (Conv3D)              (None, 64, 56, 56, 3 3104        conv3d_35[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling3d_15 (MaxPooling3D) (None, 64, 28, 28, 3 0           conv3d_28[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling3d_19 (MaxPooling3D) (None, 64, 28, 28, 3 0           conv3d_36[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_29 (Conv3D)              (None, 64, 28, 28, 3 9248        max_pooling3d_15[0][0]           \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_37 (Conv3D)              (None, 64, 28, 28, 3 9248        max_pooling3d_19[0][0]           \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_30 (Conv3D)              (None, 64, 28, 28, 3 3104        conv3d_29[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_38 (Conv3D)              (None, 64, 28, 28, 3 3104        conv3d_37[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling3d_16 (MaxPooling3D) (None, 64, 14, 14, 3 0           conv3d_30[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling3d_20 (MaxPooling3D) (None, 64, 14, 14, 3 0           conv3d_38[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "multiply_2 (Multiply)           (None, 64, 14, 14, 3 0           max_pooling3d_16[0][0]           \n",
      "                                                                 max_pooling3d_20[0][0]           \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling3d_21 (MaxPooling3D) (None, 8, 14, 14, 32 0           multiply_2[0][0]                 \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_39 (Conv3D)              (None, 8, 14, 14, 64 18496       max_pooling3d_21[0][0]           \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_40 (Conv3D)              (None, 8, 14, 14, 64 12352       conv3d_39[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling3d_22 (MaxPooling3D) (None, 4, 7, 7, 64)  0           conv3d_40[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_41 (Conv3D)              (None, 4, 7, 7, 64)  36928       max_pooling3d_22[0][0]           \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_42 (Conv3D)              (None, 4, 7, 7, 64)  12352       conv3d_41[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling3d_23 (MaxPooling3D) (None, 2, 3, 3, 64)  0           conv3d_42[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_43 (Conv3D)              (None, 2, 3, 3, 128) 73856       max_pooling3d_23[0][0]           \n",
      "__________________________________________________________________________________________________\n",
      "conv3d_44 (Conv3D)              (None, 2, 3, 3, 128) 49280       conv3d_43[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling3d_24 (MaxPooling3D) (None, 1, 1, 1, 128) 0           conv3d_44[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "flatten_2 (Flatten)             (None, 128)          0           max_pooling3d_24[0][0]           \n",
      "__________________________________________________________________________________________________\n",
      "dense_4 (Dense)                 (None, 128)          16512       flatten_2[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "dropout_2 (Dropout)             (None, 128)          0           dense_4[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "dense_5 (Dense)                 (None, 32)           4128        dropout_2[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "dense_6 (Dense)                 (None, 2)            66          dense_5[0][0]                    \n",
      "==================================================================================================\n",
      "Total params: 272,690\n",
      "Trainable params: 272,690\n",
      "Non-trainable params: 0\n",
      "__________________________________________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "inputs = Input(shape=(64,224,224,5))\n",
    "\n",
    "rgb = Lambda(get_rgb,output_shape=None)(inputs)\n",
    "opt = Lambda(get_opt,output_shape=None)(inputs)\n",
    "\n",
    "##################################################### RGB channel\n",
    "rgb = Conv3D(\n",
    "    16, kernel_size=(1,3,3), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(rgb)\n",
    "rgb = Conv3D(\n",
    "    16, kernel_size=(3,1,1), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(rgb)\n",
    "rgb = MaxPooling3D(pool_size=(1,2,2))(rgb)\n",
    "\n",
    "rgb = Conv3D(\n",
    "    16, kernel_size=(1,3,3), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(rgb)\n",
    "rgb = Conv3D(\n",
    "    16, kernel_size=(3,1,1), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(rgb)\n",
    "rgb = MaxPooling3D(pool_size=(1,2,2))(rgb)\n",
    "\n",
    "rgb = Conv3D(\n",
    "    32, kernel_size=(1,3,3), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(rgb)\n",
    "rgb = Conv3D(\n",
    "    32, kernel_size=(3,1,1), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(rgb)\n",
    "rgb = MaxPooling3D(pool_size=(1,2,2))(rgb)\n",
    "\n",
    "rgb = Conv3D(\n",
    "    32, kernel_size=(1,3,3), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(rgb)\n",
    "rgb = Conv3D(\n",
    "    32, kernel_size=(3,1,1), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(rgb)\n",
    "rgb = MaxPooling3D(pool_size=(1,2,2))(rgb)\n",
    "\n",
    "##################################################### Optical Flow channel\n",
    "opt = Conv3D(\n",
    "    16, kernel_size=(1,3,3), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(opt)\n",
    "opt = Conv3D(\n",
    "    16, kernel_size=(3,1,1), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(opt)\n",
    "opt = MaxPooling3D(pool_size=(1,2,2))(opt)\n",
    "\n",
    "opt = Conv3D(\n",
    "    16, kernel_size=(1,3,3), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(opt)\n",
    "opt = Conv3D(\n",
    "    16, kernel_size=(3,1,1), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(opt)\n",
    "opt = MaxPooling3D(pool_size=(1,2,2))(opt)\n",
    "\n",
    "opt = Conv3D(\n",
    "    32, kernel_size=(1,3,3), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(opt)\n",
    "opt = Conv3D(\n",
    "    32, kernel_size=(3,1,1), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(opt)\n",
    "opt = MaxPooling3D(pool_size=(1,2,2))(opt)\n",
    "\n",
    "opt = Conv3D(\n",
    "    32, kernel_size=(1,3,3), strides=(1,1,1), kernel_initializer='he_normal', activation='sigmoid', padding='same')(opt)\n",
    "opt = Conv3D(\n",
    "    32, kernel_size=(3,1,1), strides=(1,1,1), kernel_initializer='he_normal', activation='sigmoid', padding='same')(opt)\n",
    "opt = MaxPooling3D(pool_size=(1,2,2))(opt)\n",
    "\n",
    "\n",
    "##################################################### Fusion and Pooling\n",
    "x = Multiply()([rgb,opt])\n",
    "x = MaxPooling3D(pool_size=(8,1,1))(x)\n",
    "\n",
    "##################################################### Merging Block\n",
    "x = Conv3D(\n",
    "    64, kernel_size=(1,3,3), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(x)\n",
    "x = Conv3D(\n",
    "    64, kernel_size=(3,1,1), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(x)\n",
    "x = MaxPooling3D(pool_size=(2,2,2))(x)\n",
    "\n",
    "x = Conv3D(\n",
    "    64, kernel_size=(1,3,3), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(x)\n",
    "x = Conv3D(\n",
    "    64, kernel_size=(3,1,1), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(x)\n",
    "x = MaxPooling3D(pool_size=(2,2,2))(x)\n",
    "\n",
    "x = Conv3D(\n",
    "    128, kernel_size=(1,3,3), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(x)\n",
    "x = Conv3D(\n",
    "    128, kernel_size=(3,1,1), strides=(1,1,1), kernel_initializer='he_normal', activation='relu', padding='same')(x)\n",
    "x = MaxPooling3D(pool_size=(2,3,3))(x)\n",
    "\n",
    "##################################################### FC Layers\n",
    "x = Flatten()(x)\n",
    "x = Dense(128,activation='relu')(x)\n",
    "x = Dropout(0.2)(x)\n",
    "x = Dense(32, activation='relu')(x)\n",
    "\n",
    "# Build the model\n",
    "pred = Dense(2, activation='softmax')(x)\n",
    "model = Model(inputs=inputs, outputs=pred)\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Set the GPUs and make it parallel"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-04T16:51:53.142596Z",
     "start_time": "2020-04-04T16:51:52.367945Z"
    }
   },
   "outputs": [],
   "source": [
    "os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"0,1,2,3\"\n",
    "\n",
    "from keras.utils import multi_gpu_model   \n",
    "parallel_model = multi_gpu_model(model, gpus=4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "LBWQTN6Mm0ym"
   },
   "source": [
    "### Model Compiling"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-04T17:28:09.335822Z",
     "start_time": "2020-04-04T17:28:09.245309Z"
    },
    "colab": {},
    "colab_type": "code",
    "id": "EGID3emEm0yn"
   },
   "outputs": [],
   "source": [
    "from keras.optimizers import Adam, SGD\n",
    "\n",
    "sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)\n",
    "parallel_model.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "2TZgW6QR8oqH"
   },
   "source": [
    "### Set Callbacks"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Learning Rate Scheduler"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-04T17:28:09.882036Z",
     "start_time": "2020-04-04T17:28:09.873755Z"
    }
   },
   "outputs": [],
   "source": [
    "import keras.backend as K\n",
    "from keras.callbacks import LearningRateScheduler\n",
    "\n",
    "def scheduler(epoch):\n",
    "    if epoch % 10 == 0 and epoch != 0:\n",
    "        lr = K.get_value(parallel_model.optimizer.lr)\n",
    "        K.set_value(parallel_model.optimizer.lr, lr * 0.7)\n",
    "    return K.get_value(parallel_model.optimizer.lr)\n",
    "\n",
    "reduce_lr = LearningRateScheduler(scheduler)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-02T06:06:34.689926Z",
     "start_time": "2020-04-02T06:06:34.684821Z"
    }
   },
   "source": [
    "- Saving the best model and training logs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-04T17:28:10.155451Z",
     "start_time": "2020-04-04T17:28:10.146371Z"
    }
   },
   "outputs": [],
   "source": [
    "from keras.callbacks import ModelCheckpoint, CSVLogger\n",
    "import keras\n",
    "\n",
    "class MyCbk(keras.callbacks.Callback):\n",
    "\n",
    "    def __init__(self, model):\n",
    "         self.model_to_save = model\n",
    "\n",
    "    def on_epoch_end(self, epoch, logs=None):\n",
    "        self.model_to_save.save('Logs/model_at_epoch_%d.h5' % (epoch+1))\n",
    "\n",
    "check_point = MyCbk(model)\n",
    "\n",
    "\n",
    "filename = 'Logs/ours_log.csv'\n",
    "csv_logger = CSVLogger(filename, separator=',', append=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-04T17:28:10.261900Z",
     "start_time": "2020-04-04T17:28:10.258067Z"
    }
   },
   "outputs": [],
   "source": [
    "callbacks_list = [check_point, csv_logger, reduce_lr]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "DG5y04tym0yr"
   },
   "source": [
    "### Model Training"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- set essential params"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-04T17:28:10.798973Z",
     "start_time": "2020-04-04T17:28:10.794885Z"
    }
   },
   "outputs": [],
   "source": [
    "num_epochs  = 30\n",
    "num_workers = 16\n",
    "batch_size  = 8"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- init data generator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-04T17:28:11.079793Z",
     "start_time": "2020-04-04T17:28:11.069620Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found 200 files belonging to 2 classes.\n",
      "     Fight :  0\n",
      "  NonFight :  1\n",
      "Found 45 files belonging to 2 classes.\n",
      "     Fight :  0\n",
      "  NonFight :  1\n"
     ]
    }
   ],
   "source": [
    "dataset = 'ViolentFlow-opt'\n",
    "\n",
    "train_generator = DataGenerator(directory='../Datasets/{}/train'.format(dataset), \n",
    "                                batch_size=batch_size, \n",
    "                                data_augmentation=True)\n",
    "\n",
    "val_generator = DataGenerator(directory='../Datasets/{}/val'.format(dataset),\n",
    "                              batch_size=batch_size, \n",
    "                              data_augmentation=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- start to train"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-04T17:36:13.080206Z",
     "start_time": "2020-04-04T17:28:11.628484Z"
    },
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 52
    },
    "colab_type": "code",
    "executionInfo": {
     "elapsed": 40622,
     "status": "error",
     "timestamp": 1561260510157,
     "user": {
      "displayName": "XXXXg CXXXX",
      "photoUrl": "",
      "userId": "04701665026083715772"
     },
     "user_tz": -480
    },
    "id": "wTd5cDHBm0yt",
    "outputId": "099af51f-6278-4284-db46-6ade4b7a9fda"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/30\n",
      "25/25 [==============================] - 37s 1s/step - loss: 0.0025 - accuracy: 1.0000 - val_loss: 2.2915e-04 - val_accuracy: 0.8444\n",
      "Epoch 2/30\n",
      "25/25 [==============================] - 33s 1s/step - loss: 7.4970 - accuracy: 0.5350 - val_loss: 9.6709 - val_accuracy: 0.4889\n",
      "Epoch 3/30\n",
      "25/25 [==============================] - 33s 1s/step - loss: 8.0590 - accuracy: 0.5000 - val_loss: 3.2236 - val_accuracy: 0.4889\n",
      "Epoch 4/30\n",
      "25/25 [==============================] - 33s 1s/step - loss: 8.0590 - accuracy: 0.5000 - val_loss: 1.1921e-07 - val_accuracy: 0.4889\n",
      "Epoch 5/30\n",
      "25/25 [==============================] - 33s 1s/step - loss: 8.0590 - accuracy: 0.5000 - val_loss: 6.4472 - val_accuracy: 0.4889\n",
      "Epoch 6/30\n",
      "25/25 [==============================] - 33s 1s/step - loss: 8.0590 - accuracy: 0.5000 - val_loss: 9.6709 - val_accuracy: 0.4889\n",
      "Epoch 7/30\n",
      "25/25 [==============================] - 33s 1s/step - loss: 8.0590 - accuracy: 0.5000 - val_loss: 1.1921e-07 - val_accuracy: 0.4889\n",
      "Epoch 8/30\n",
      "25/25 [==============================] - 33s 1s/step - loss: 8.0590 - accuracy: 0.5000 - val_loss: 9.6709 - val_accuracy: 0.4889\n",
      "Epoch 9/30\n",
      "25/25 [==============================] - 33s 1s/step - loss: 8.0590 - accuracy: 0.5000 - val_loss: 6.4472 - val_accuracy: 0.4889\n",
      "Epoch 10/30\n",
      "25/25 [==============================] - 33s 1s/step - loss: 8.0590 - accuracy: 0.5000 - val_loss: 6.4472 - val_accuracy: 0.4889\n",
      "Epoch 11/30\n",
      "25/25 [==============================] - 33s 1s/step - loss: 8.0590 - accuracy: 0.5000 - val_loss: 6.4472 - val_accuracy: 0.4889\n",
      "Epoch 12/30\n",
      "25/25 [==============================] - 33s 1s/step - loss: 8.0590 - accuracy: 0.5000 - val_loss: 9.6709 - val_accuracy: 0.4889\n",
      "Epoch 13/30\n",
      "25/25 [==============================] - 33s 1s/step - loss: 8.0590 - accuracy: 0.5000 - val_loss: 6.4472 - val_accuracy: 0.4889\n",
      "Epoch 14/30\n",
      "25/25 [==============================] - 33s 1s/step - loss: 8.0590 - accuracy: 0.5000 - val_loss: 9.6709 - val_accuracy: 0.4889\n",
      "Epoch 15/30\n",
      " 7/25 [=======>......................] - ETA: 23s - loss: 6.9078 - accuracy: 0.5714"
     ]
    },
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-59-37dea5b50fba>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      8\u001b[0m     \u001b[0mmax_queue_size\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      9\u001b[0m     \u001b[0msteps_per_epoch\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtrain_generator\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 10\u001b[0;31m     validation_steps=len(val_generator))\n\u001b[0m",
      "\u001b[0;32m~/anaconda3/lib/python3.7/site-packages/keras/legacy/interfaces.py\u001b[0m in \u001b[0;36mwrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m     89\u001b[0m                 warnings.warn('Update your `' + object_name + '` call to the ' +\n\u001b[1;32m     90\u001b[0m                               'Keras 2 API: ' + signature, stacklevel=2)\n\u001b[0;32m---> 91\u001b[0;31m             \u001b[0;32mreturn\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     92\u001b[0m         \u001b[0mwrapper\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_original_function\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     93\u001b[0m         \u001b[0;32mreturn\u001b[0m \u001b[0mwrapper\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.7/site-packages/keras/engine/training.py\u001b[0m in \u001b[0;36mfit_generator\u001b[0;34m(self, generator, steps_per_epoch, epochs, verbose, callbacks, validation_data, validation_steps, validation_freq, class_weight, max_queue_size, workers, use_multiprocessing, shuffle, initial_epoch)\u001b[0m\n\u001b[1;32m   1730\u001b[0m             \u001b[0muse_multiprocessing\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0muse_multiprocessing\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1731\u001b[0m             \u001b[0mshuffle\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mshuffle\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1732\u001b[0;31m             initial_epoch=initial_epoch)\n\u001b[0m\u001b[1;32m   1733\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1734\u001b[0m     \u001b[0;34m@\u001b[0m\u001b[0minterfaces\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlegacy_generator_methods_support\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.7/site-packages/keras/engine/training_generator.py\u001b[0m in \u001b[0;36mfit_generator\u001b[0;34m(model, generator, steps_per_epoch, epochs, verbose, callbacks, validation_data, validation_steps, validation_freq, class_weight, max_queue_size, workers, use_multiprocessing, shuffle, initial_epoch)\u001b[0m\n\u001b[1;32m    183\u001b[0m             \u001b[0mbatch_index\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    184\u001b[0m             \u001b[0;32mwhile\u001b[0m \u001b[0msteps_done\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0msteps_per_epoch\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 185\u001b[0;31m                 \u001b[0mgenerator_output\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0moutput_generator\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    186\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    187\u001b[0m                 \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mhasattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgenerator_output\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'__len__'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.7/site-packages/keras/utils/data_utils.py\u001b[0m in \u001b[0;36mget\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    608\u001b[0m                 \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    609\u001b[0m                     \u001b[0mfuture\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mqueue\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mblock\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 610\u001b[0;31m                     \u001b[0minputs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfuture\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m30\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    611\u001b[0m                 \u001b[0;32mexcept\u001b[0m \u001b[0mmp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTimeoutError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    612\u001b[0m                     \u001b[0midx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfuture\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0midx\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.7/multiprocessing/pool.py\u001b[0m in \u001b[0;36mget\u001b[0;34m(self, timeout)\u001b[0m\n\u001b[1;32m    649\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    650\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 651\u001b[0;31m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwait\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    652\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mready\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    653\u001b[0m             \u001b[0;32mraise\u001b[0m \u001b[0mTimeoutError\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.7/multiprocessing/pool.py\u001b[0m in \u001b[0;36mwait\u001b[0;34m(self, timeout)\u001b[0m\n\u001b[1;32m    646\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    647\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mwait\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 648\u001b[0;31m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_event\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwait\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    649\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    650\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.7/threading.py\u001b[0m in \u001b[0;36mwait\u001b[0;34m(self, timeout)\u001b[0m\n\u001b[1;32m    550\u001b[0m             \u001b[0msignaled\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_flag\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    551\u001b[0m             \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0msignaled\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 552\u001b[0;31m                 \u001b[0msignaled\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_cond\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwait\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    553\u001b[0m             \u001b[0;32mreturn\u001b[0m \u001b[0msignaled\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    554\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.7/threading.py\u001b[0m in \u001b[0;36mwait\u001b[0;34m(self, timeout)\u001b[0m\n\u001b[1;32m    298\u001b[0m             \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    299\u001b[0m                 \u001b[0;32mif\u001b[0m \u001b[0mtimeout\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 300\u001b[0;31m                     \u001b[0mgotit\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mwaiter\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0macquire\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    301\u001b[0m                 \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    302\u001b[0m                     \u001b[0mgotit\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mwaiter\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0macquire\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
     ]
    }
   ],
   "source": [
    "hist = parallel_model.fit_generator(\n",
    "    generator=train_generator, \n",
    "    validation_data=val_generator,\n",
    "    callbacks=callbacks_list,\n",
    "    verbose=1, \n",
    "    epochs=num_epochs,\n",
    "    workers=num_workers ,\n",
    "    max_queue_size=4,\n",
    "    steps_per_epoch=len(train_generator),\n",
    "    validation_steps=len(val_generator))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "colab": {
   "collapsed_sections": [],
   "name": "C3D.ipynb",
   "provenance": [],
   "version": "0.3.2"
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
